package server.connector.http;

import server.HttpRequest;
import server.connector.HttpRequestFacade;
import server.util.ParameterMap;
import server.util.RequestUtil;

import javax.servlet.ServletInputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;

public abstract class HttpRequestBase {

    //不太懂的
    //身份验证类型,不懂
    protected String authType = null;
    //请求头Authorization的值,一般用于存放账号密码
    protected String authorization = null;
// ---------------------------------------------------------------------------------------------------------------------------------------------
    //使用的协议
    protected String scheme = null;
    //安全连接?
    protected boolean secure = false;
    //连接器
    protected HttpConnector connector = null;
    //连接的socket
    protected Socket socket = null;
    //此请求的远程客户端的InetAddress
    protected InetAddress inet = null;
    //输入流(实际是ScoketInputStream)
    protected InputStream input = null;
    //请求方法
    protected String method = null;
    //请求URI
    protected String requestURI = null;
    //请求协议版本
    protected String protocol = null;
    //查询字符串
    protected String queryString = null;
    //请求参数是否被解析过
    protected boolean parsed = false;
    //存放请求参数
    protected ParameterMap<String, String[]> parameters = null;
    //存放所有的请求头
    protected HashMap<String, ArrayList<String>> headers = new HashMap<>();
    protected int contentLength = -1;
    protected String contentType = null;
    protected String characterEncoding = null;
    //存放客户端接受语言的Locale
    protected ArrayList<Locale> locales = new ArrayList<>();
    //请求的服务器端口
    protected int serverPort = -1;
    //请求的服务器主机名
    protected String serverName = null;
    //存放cookie
    protected ArrayList<Cookie> cookies = new ArrayList<>();
    //session id
    protected String requestedSessionId = null;
    //sessionID来自Cookie?
    protected boolean requestedSessionIdFromCookie = false;
    //sessionID来自url?
    protected boolean requestedSessionIdFromURL = false;
    //读取请求体的流
    protected ServletInputStream stream = null;
    //读取请求体的Reader
    protected BufferedReader reader = null;
    //存放属性
    protected HashMap<String, Object> attributes = new HashMap<>();
    //外观类
    protected HttpRequestFacade requestFacade = null;
    //响应对象
    protected HttpResponseImpl response = null;
    //解码后的uri(把%xx转为字符)
    protected String decodedRequestURI = null;

    //解析请求参数,如果请求体中也有参数,一并解析
    protected void parseParameters() {
        //解析一次就行
        if (parsed)
            return;
        if (parameters == null)
            parameters = new ParameterMap<>();
        //卸锁
        parameters.setLocked(false);
        //开始解析
        HttpRequestImpl httpRequest = (HttpRequestImpl)this;
        String encoding = httpRequest.getCharacterEncoding();
        //如果请求方未指明字符集编码格式,按默认格式解析
        if (encoding == null)
            encoding = Constants.DEFAULT_REQUEST_ENCODING;
        //解析查询字符串中的参数
        String queryString = httpRequest.getQueryString();
        try {
            RequestUtil.parseParameters(parameters, queryString, encoding);
        } catch (UnsupportedEncodingException e) {

        }
        //如果请求体中包含参数,解析
        String contentType = httpRequest.getContentType();
        if (contentType == null)
            contentType = "";
        int semicolonIndex = contentType.indexOf(';');
        //找到主类型
        if (semicolonIndex >= 0) {
            contentType = contentType.substring(0, semicolonIndex).trim();
        } else {
            contentType = contentType.trim();
        }
        //post请求的请求体中也可以含有参数(当content-type=application/x-www-form-urlencode且content-length>0时)
        //stream或reader不为null时,请求体可能被Servlet读过,无法解析
        if ("POST".equals(httpRequest.getMethod()) && httpRequest.getContentLength() > 0
                && this.stream == null && this.reader == null && "application/x-www-form-urlencoded".equals(contentType)) {
            try {
                int maxRead = httpRequest.getContentLength();
                byte[] buffer = new byte[maxRead];
                int readCount = 0;
                ServletInputStream is = httpRequest.getInputStream();
                while (readCount < maxRead) {
                    int len = is.read(buffer, readCount, maxRead - readCount);
                    if (len < 0)
                        break;
                    readCount += len;
                }
                is.close();
                if (readCount < maxRead) {
                    String message = "content-length提示要读取" + maxRead +
                            "个字节,实际只能读取" + readCount + "个字节";
                    throw new RuntimeException(message);
                }
                RequestUtil.parseParameters(parameters, buffer, encoding);
            } catch (UnsupportedEncodingException ue) {

            } catch (IOException e) {
                throw new RuntimeException("读取POST请求参数失败:" + e.getMessage());
            }
        }
        //解析完成
        //上锁
        parameters.setLocked(true);
        parsed = true;
    }
    //添加请求头
    public void addHeader(String name, String value) {
        name = name.toLowerCase();
        synchronized (headers) {
            ArrayList<String> values = headers.get(name);
            if (values == null) {
                values = new ArrayList<>();
                headers.put(name, values);
            }
            values.add(value);
        }
    }
    //添加接受的地区语言
    public void addLocale(Locale locale) {
        synchronized (locales) {
            locales.add(locale);
        }

    }
    //添加cookie
    public void addCookie(Cookie cookie) {
        synchronized (cookies) {
            cookies.add(cookie);
        }
    }

    //创建封装好的输入流,隐藏对端分块发送的处理细节
    public ServletInputStream createInputStream() throws IOException {
        return new HttpRequestStream((HttpRequestImpl) this, response);
    }

    //读完当前请求请求体的全部内容
    public void finishRequest() throws IOException {
        HttpRequestImpl httpRequest = (HttpRequestImpl)this;
        //如果读请求体的流未打开并且请求体有内容要读且协议版本是1.1(1.0直接关闭套接字就行,因为1.1有长连接,需要读完请求内容才能读下一个报文)
        if (reader == null && stream == null && httpRequest.getContentLength() != 0
                && httpRequest.getProtocol() != null && "HTTP/1.1".equals(httpRequest.getProtocol())) {
            httpRequest.getInputStream();
        }
        //关闭流,关闭时会读完全部内容
        if (reader != null) {
            try {
                reader.close();
            } catch (Exception e) {

            }
        }
        if (stream != null) {
            try {
                stream.close();
            } catch (Exception e) {
            }
        }
    }
    //重新使用该对象,将之前的字段值清零
    public void reuse() {
        //connector和requestFacade一直都不变,不用清零
        secure = false;
        scheme = null;
        socket = null;
        inet = null;
        input = null;
        method = null;
        requestURI = null;
        protocol = null;
        queryString = null;
        parsed = false;
        if (parameters != null) {
            parameters.setLocked(false);
            parameters.clear();
        }
        //Servlet程序执行完毕之后才会清除,单线程操作,不需要加锁
        headers.clear();
        contentLength = -1;
        contentType = null;
        characterEncoding = null;
        locales.clear();
        serverName = null;
        serverPort = -1;
        cookies.clear();
        requestedSessionId = null;
        requestedSessionIdFromCookie = false;
        requestedSessionIdFromURL = false;
        stream = null;
        reader = null;
        attributes.clear();
        response = null;
        authType = null;
        authorization = null;
        decodedRequestURI = null;
    }
    //清除所有请求头
    public void clearHeaders() {
        synchronized (headers) {
            headers.clear();
        }
    }
    //清除所有Cookie
    public void clearCookies() {
        synchronized (cookies) {
            cookies.clear();
        }
    }
    //清除所有Locale
    public void clearLocales() {
        synchronized (locales) {
            locales.clear();
        }
    }
    //清除所有参数
    public void clearParameters() {
        if (parameters == null)
            return;
        parameters.setLocked(false);
        parameters.clear();
    }


    //getter--------------------------------------------------------------------------
    //获取远程客户端的InetAddress
    public InetAddress getInet() {
        return this.inet;
    }
    //获取输入流
    public InputStream getStream() {
        return this.input;
    }
    //获取外观类
    public HttpRequestFacade getRequestFacade() {
        if (requestFacade == null)
            requestFacade = new HttpRequestFacade((HttpServletRequest) this);
        return requestFacade;
    }
    //获取解码后的uri(把%xx转为字符)
    public String getDecodedRequestURI() {
        if (decodedRequestURI == null)
            decodedRequestURI = RequestUtil.URLDecode(((HttpServletRequest)this).getRequestURI());
        return decodedRequestURI;
    }
    //setter--------------------------------------------------------------------------
    //设置远程客户端的InetAddress
    public void setQueryString(String queryString) {
        this.queryString = queryString;
    }
    public void setInet(InetAddress inet) {
        this.inet = inet;
    }
    public void setConnector(HttpConnector connector) {
        this.connector = connector;
    }
    public void setAuthType(String authType) {
        this.authType = authType;
    }
    public void setRequestedSessionId(String sessionId) {
        this.requestedSessionId = sessionId;
    }
    public void setRequestURI(String requestURI) {
        this.requestURI = requestURI;
    }
    public void setProtocol(String protocol) {
        this.protocol = protocol;
    }
    public void setContentLength(int length) {
        this.contentLength = length;
    }
    public void setContentType(String type) {
        this.contentType = type;
        if (type.indexOf(';') >= 0)
            characterEncoding = RequestUtil.parseCharacterEncoding(type);
    }
    public void setScheme(String scheme) {
        this.scheme = scheme;
    }
    public void setSecure(boolean secure) {
        this.secure = secure;
    }

    public void setServerPort(int port) {
        this.serverPort = port;
    }
    public void setServerName(String name) {
        this.serverName = name;
    }
    public void setRequestedSessionIdFromCookie(boolean flag) {
        this.requestedSessionIdFromCookie = flag;
    }
    public void setRequestedSessionIdFromURL(boolean flag) {
        this.requestedSessionIdFromURL = flag;
    }
    public void setMethod(String method) {
        this.method = method;
    }
    public void setSocket(Socket socket) {
        this.socket = socket;
    }
    public void setAuthorization(String authorization) {
        this.authorization = authorization;
    }
    //设置输入流
    public void setStream(InputStream input) {
        this.input = input;
    }
    //设置响应对象
    public void setResponse(HttpResponseImpl response) {
        this.response = response;
    }


}
